#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#include "Task.hpp"

static const int processnum = 10; // 要创建的进程数量
std::vector<task_t> tasks;

// 先描述
class Channel
{
public:
    Channel(int cmdfd, pid_t slaverid, const std::string &processname)
        : _cmdfd(cmdfd), _slaverid(slaverid), _processname(processname)
    {
    }

public:
    int _cmdfd;               // 发布任务的文件描述符（负责写）
    pid_t _slaverid;          // 子进程的pid（负责读）
    std::string _processname; // 子进程的名字
};

// 子进程执行的功能，做的任务
void slaver()
{
    while (true)
    {
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(int));
        if(n == sizeof(int))
        {
            // 执行cmdcode对应的任务列表
            std::cout << "child-[" << getpid() << "]-slaver say@ get a cmdcode: " << cmdcode << std::endl;
            if(cmdcode >= 0 && cmdcode < tasks.size())
                tasks[cmdcode]();
        }
        else if(n == 0)
            break;
    }
    
}

// 初始化
void InitProcessPool(std::vector<Channel>* channels)
{
    for (size_t i = 0; i < processnum; i++)
    {
        // 创建管道
        int pipefd[2];
        int n = pipe(pipefd);
        if(n < 0)
        {
            perror("pipe");
            return;
        }
        // 此时 pipefd[0] = 3, pipefd[1] = 4
        // 创建子进程
        pid_t id = fork();
        if(id == 0)
        {
            // child
            close(pipefd[1]);   // 关闭写端
            
            dup2(pipefd[0], 0); //标准输入0号文件描述符指向 读端管道文件
            slaver();           // 子进程执行的函数功能
            exit(0);
        }
        // father
        close(pipefd[0]);       // 关闭读端
        //添加channel字段
        std::string name = "process-" + std::to_string(i);
        channels->push_back(Channel(pipefd[1], id, name));
    }
}

// 控制子进程，给自己才能发布任务
void Menu()
{
    std::cout << "################################################" << std::endl;
    std::cout << "# 1. 刷新日志             2. 更新野区           #" << std::endl;
    std::cout << "# 3. 刷新金币             4. 获取点Juana        #" << std::endl;
    std::cout << "# 5.释放技能              0. 退出               #" << std::endl;
    std::cout << "################################################" << std::endl;
}
void CtrlSlaver(std::vector<Channel>& channels)
{
    int which = 0;
    int cnt = 10;
    while (cnt--)   // 轮询10次
    {
        // int select = 0;
        // Menu();
        // std::cout << "Please Enter@: ";
        // std::cin >> select;
        // if(select <= 0 || select > 5) break;
        // // 选择任务
        // int cmdcode = select-1;

        // 选择任务
        int cmdcode = rand() % tasks.size();

        // 轮询进程
        std::cout << "father say: cmdcode: " << cmdcode << ", already sendto: "
            << channels[which]._slaverid << ", processname: " << channels[which]._processname << std::endl;
        // 发送任务
        write(channels[which]._cmdfd, &cmdcode, sizeof(cmdcode));
        which++;
        which %= channels.size();
        sleep(1);
    }
}

// 清理收尾
void QuitProcess(std::vector<Channel>& channels)
{
    for(auto& ch : channels)
    {
        close(ch._cmdfd);
    }
    sleep(3);
    for(auto& ch : channels)
    {
        waitpid(ch._slaverid, nullptr, 0);  // 等待子进程
    }
}


int main()
{
    LoadTask(&tasks);

    srand(time(0) ^ getpid() ^ 1023);
    // 再组织
    std::vector<Channel> channels;
    // 初始化
    InitProcessPool(&channels);

    // 控制子进程，给自己才能发布任务
    CtrlSlaver(channels);

    // 清理收尾
    QuitProcess(channels);
    return 0;
}